
#include "apdu_lib_container_mgr.h"
#include "apdu_lib_common.h"

#include "../apdu.core/apdu.h"

#include "../../mk_lib/mk_auto_ptr.h"
#include "../../mk_lib/mk_utility.h"
#include "../../mk_lib/mk_node_list.h"

#include <stdlib.h>
#include <string.h>
#include "../apdu.algo/mac.h"


extern int	g_sw;
int app_create_container( HANDLE devHandle,int app_id, char * container_name, int * container_id )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_create_container(app_id, container_name);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	* container_id = pData[0] * 256 + pData[1];
	return 0;
}

int app_open_container( HANDLE devHandle, int app_id, char * container_name, int * container_id )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_open_container(app_id, container_name);

	mk_auto_ptr<apdu> ap(newApdu);
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	* container_id = pData[0] * 256 + pData[1];

	return 0;
}

int app_close_container( HANDLE devHandle, int app_id, int container_id )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_close_container(app_id, container_id);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_enum_containers( HANDLE devHandle, int app_id, char * container_names, int * buff_size )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_enum_container(app_id);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000 && g_sw != 0x6A9E)
	{
		return 2;
	}

	int data_len =0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	if(*buff_size < data_len)
	{
		return 3;
	}
	*buff_size = data_len;
	memcpy(container_names, pData, data_len);
	return 0;
}

int app_delete_container( HANDLE devHandle, int app_id, char * container_name )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_delete_container(app_id, container_name);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_get_container_info( HANDLE devHandle, int app_id, char * container_name, 
						   int * type, unsigned long * sign_key_len, unsigned long * exch_key_len, 
						   int * sign_cert_flag, int * exch_cert_flag )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_get_containter_info(app_id, container_name);

	mk_auto_ptr<apdu> ap(newApdu);

	
	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len =0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	int pos = 0;

	* type = pData[pos ++];
	memcpy(sign_key_len, pData + pos, 4);
	pos += 4;

	memcpy(exch_key_len, pData + pos, 4);
	pos += 4;

	* sign_cert_flag = pData[pos++];
	* exch_cert_flag = pData[pos++];

	mk_utility::reverse_bytes(sign_key_len, 4);
	mk_utility::reverse_bytes(exch_key_len, 4);

	return 0;
}

int app_get_container_name(HANDLE devHandle, int app_id, int container_id, 
						   char * containerName, int * nameLen)
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_get_container_name_by_id(app_id, container_id);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000) 
	{
		return 2;
	}

	int data_len =0;
	unsigned char * pData = newApdu->get_response_data(&data_len);
	if(*nameLen < data_len)
	{
		*nameLen = data_len;
		return 3;
	}

	memcpy(containerName, pData, data_len);
	*nameLen = data_len;

	return 0;
}

int app_import_certificate( HANDLE devHandle, int app_id, int container_id, int cert_type,
						   unsigned char * cert_data, int data_len )
{
	int rv = 0;
	int max_transmit_len = get_max_transmit_len();

	apdu * headApdu = get_apdu_mgr()->create_apdu_import_certificate_head(app_id, container_id, cert_type, data_len);
	headApdu->set_not_last_ins();

	mk_auto_ptr<apdu> ap(headApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle, headApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int apdu_num = (data_len + max_transmit_len - 1) / max_transmit_len;
	apdu * newApdu  = NULL;

	for(int i = 0; i < apdu_num ; i ++)
	{
		unsigned char * pBuff = cert_data + i * max_transmit_len;
		int len = data_len - i * max_transmit_len;
		if(len > max_transmit_len)
			len = max_transmit_len;

		newApdu = get_apdu_mgr()->create_apdu_transmit_more_data(headApdu, pBuff, len);

		if( i < apdu_num - 1)
			newApdu->set_not_last_ins();
		else
			newApdu->set_last_ins();
		
		if( 0 != get_dev_mgr()->transmit_apdu(devHandle, newApdu, &g_sw))
		{
			rv = 1;
			break;
		}

		if(g_sw != 0x9000)
		{
			rv = 2;
			break;
		}

		delete newApdu;
		newApdu = NULL;
	}

	if(newApdu)
	{
		delete newApdu;
	}

	return rv;
}

int app_export_certificate( HANDLE devHandle, int is_first_package, int app_id, int container_id,
						   int cert_type, unsigned char * cert_data, int * cert_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_export_certificate(app_id, container_id, cert_type);
	
	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000 && g_sw != 0x6A9E)
	{
		return 2;
	}

	int data_len =0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	if(*cert_len < data_len)
	{
		* cert_len = data_len;
		return 3;
	}
	
	if(is_first_package)
	{
		* cert_len = data_len - 4;
		memcpy(cert_data, pData + 4, data_len - 4);
	}
	else
	{
		* cert_len = data_len;
		memcpy(cert_data, pData, data_len);
	}

	return 0;
}


int app_delete_keypair(HANDLE devHandle,int app_id, int container_id, int key_spec)
{
	apdu * newApdu  =  NULL;
	newApdu = get_rsa_mgr()->create_apdu_delete_keypair(app_id, container_id, key_spec);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_delete_certificate(HANDLE devHandle,int app_id, int container_id, int key_spec)
{
	apdu * newApdu  =  NULL;
	newApdu = get_rsa_mgr()->create_apdu_delete_certificate(app_id, container_id, key_spec);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_set_container_ex_info( HANDLE devHandle, int app_id, int container_id, int offset, int data_len, unsigned char* pData )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_set_container_ex_info(app_id, container_id, offset, pData, data_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_get_container_ex_info( HANDLE devHandle, int app_id, int container_id, int offset, int *info_len, unsigned char* pInfo )
{
	apdu * newApdu  =  NULL;
	newApdu = get_apdu_mgr()->create_apdu_get_container_ex_info(app_id, container_id, offset, *info_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len =0;
	unsigned char * pData = newApdu->get_response_data(&data_len);

	if(*info_len < data_len)
	{
		*info_len = data_len;
		return 3;
	}
	
	*info_len = data_len;
	memcpy(pInfo, pData, data_len);

	return 0;
}
